// Floyd算法模版（洛谷）
// 测试链接 : https://www.luogu.com.cn/problem/P2910
// 提交以下所有代码，可以直接通过

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int MAXN = 101;
const int MAXM = 10001;

int path[MAXM];
int dist[MAXN][MAXN];

int n, m;
const int INF = 0x3f3f3f3f;

// 初始时设置任意两点之间的最短距离为无穷大，表示任何路不存在
void build()
{
    memset(dist, 0x3f, sizeof(dist));
}

void floyd()
{
    // O(N^3) 的过程
    // 枚举每个跳板
    // 注意，跳板要最先枚举！跳板要最先枚举！跳板要最先枚举！
    for(int bridge = 0; bridge < n; ++bridge) // 跳板
    {
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                // i -> .....bridge .... -> j
                // distance[i][j] 能不能缩短
                // distance[i][j] = min(distance[i][j] , distance[i][bridge] + distance[bridge][j])
                if(dist[i][bridge] != INF && dist[bridge][j] != INF
                    && dist[i][bridge] + dist[bridge][j] < dist[i][j])
                {
                    dist[i][j] = dist[i][bridge] + dist[bridge][j];
                }
            }
        }
    }
}

int main()
{
    cin >> n >> m;
    for(int i = 0; i < m; ++i)
    {
        cin >> path[i];
        --path[i]; // 将坐标转成 0 ~ n - 1
    }

    // 这道题给的图是邻接矩阵的形式
    // 任意两点之间的边权都会给定
    // 所以显得 dist 初始化不太必要
    // 但是一般情况下，dist 初始化一定要做
    build();
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < n; ++j)
        {
            cin >> dist[i][j];
        }
    }

    floyd();
    int ans = 0;
    for(int i = 1; i < m; ++i)
    {
        ans += dist[path[i - 1]][path[i]];
    }
    cout << ans << endl;

    return 0;
}